package com.shopping.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shopping.common.constant.ProductConstant;
import com.shopping.common.to.SkuReductionTo;
import com.shopping.common.to.SpuBoundTo;
import com.shopping.common.to.es.SkuEsModel;
import com.shopping.common.utils.Constant;
import com.shopping.common.utils.PageUtils;
import com.shopping.common.utils.Query;
import com.shopping.common.utils.R;
import com.shopping.common.vo.SkuHasStockVo;
import com.shopping.product.dao.SpuInfoDao;
import com.shopping.product.entity.*;
import com.shopping.product.feign.CouponFeignService;
import com.shopping.product.feign.SearchFeignService;
import com.shopping.product.feign.WareFeignService;
import com.shopping.product.service.*;
import com.shopping.product.vo.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Resource
    SpuInfoDescService spuInfoDescService;

    @Resource
    SpuImagesServiceImpl spuImagesService;

    @Resource
    AttrService attrService;

    @Resource
    ProductAttrValueService attrValueService;

    @Resource
    SkuInfoService skuInfoService;

    @Resource
    SkuImagesService skuImagesService;

    @Resource
    SkuSaleAttrValueService skuSaleAttrValueService;

    @Resource
    CouponFeignService couponFeignService;

    @Resource
    BrandService brandService;

    @Resource
    CategoryService categoryService;

    @Resource
    WareFeignService wareFeignService;

    @Resource
    SearchFeignService searchFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void saveSpuInfo(SpuSaveVo spuSaveVo) {
        //1.保存基本信息;pms_spu_info
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        BeanUtils.copyProperties(spuSaveVo, spuInfoEntity);
        spuInfoEntity.setCreateTime(new Date());
        spuInfoEntity.setUpdateTime(new Date());
        this.saveBaseSpuInfo(spuInfoEntity);

        //2.保存spu的描述信息;pms_spu_info_desc
        List<String> decript = spuSaveVo.getDecript();
        SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
        descEntity.setSpuId(spuInfoEntity.getId());
        descEntity.setDecript(String.join(",", decript));
        System.out.println("descEntity.getSpuId() = " + descEntity.getSpuId());
        spuInfoDescService.saveSpuInfoDesc(descEntity);

        //3.保存spu的图片集;pms_spu_images
        List<String> images = spuSaveVo.getImages();
        spuImagesService.saveImages(spuInfoEntity.getId(), images);

        //4.保存spu的规格参数;pms_product_attr_value
        List<BaseAttrs> baseAttrs = spuSaveVo.getBaseAttrs();
        List<ProductAttrValueEntity> collect = baseAttrs.stream().map(attr -> {
            ProductAttrValueEntity valueEntity = new ProductAttrValueEntity();
            valueEntity.setAttrId(attr.getAttrId());
            AttrEntity id = attrService.getById(attr.getAttrId());
            valueEntity.setAttrName(id.getAttrName());
            valueEntity.setAttrValue(attr.getAttrValues());
            valueEntity.setQuickShow(attr.getShowDesc());
            valueEntity.setSpuId(spuInfoEntity.getId());
            return valueEntity;
        }).collect(Collectors.toList());
        attrValueService.saveProductAttr(collect);

        //5保存spu的积分信息;shopping_sms -> sms_spu_bounds
        Bounds bounds = spuSaveVo.getBounds();
        SpuBoundTo spuBoundTo = new SpuBoundTo();
        BeanUtils.copyProperties(bounds, spuBoundTo);
        spuBoundTo.setSpuId(spuInfoEntity.getId());
        R r1 = couponFeignService.saveSpuBounds(spuBoundTo);
        if (r1.getCode() != 0) {
            log.error("远程保存spu积分信息失败");
        }

        //6.保存当前spu对应的sku信息
        List<Skus> skus = spuSaveVo.getSkus();
        if (skus != null && skus.size() > 0) {
            saveSkus(skus, spuInfoEntity);
        }
    }

    private void addWareSku(Long skuId, Long wareId) {
        WareSkuEntity wareSkuEntity = new WareSkuEntity();
        wareSkuEntity.setSkuId(skuId);
        wareSkuEntity.setWareId(wareId);
        wareFeignService.save(wareSkuEntity);
    }


    /**
     * 提供给saveSpuInfo使用
     */
    private void saveSkus(List<Skus> skus, SpuInfoEntity spuInfoEntity) {
        skus.forEach(item -> {
            String defaultImg = "";
            for (Images image : item.getImages()) {
                if (image.getDefaultImg() == 1) {
                    defaultImg = image.getImgUrl();
                }
            }

            SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
            BeanUtils.copyProperties(item, skuInfoEntity);
            skuInfoEntity.setBrandId(spuInfoEntity.getBrandId());
            skuInfoEntity.setCatalogId(spuInfoEntity.getCatalogId());
            skuInfoEntity.setSaleCount(0L);
            skuInfoEntity.setSpuId(spuInfoEntity.getId());
            skuInfoEntity.setSkuDefaultImg(defaultImg);

            //6.1 sku的基本信息;pms_spu_info
            skuInfoService.saveSkuInfo(skuInfoEntity);
            Long skuId = skuInfoEntity.getSkuId();
            // todo 过滤空的imgUrl失效了
            List<SkuImagesEntity> imagesEntities = item.getImages()
                    .stream()
                    .map(img -> {
                        SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                        skuImagesEntity.setSkuId(skuId);
                        skuImagesEntity.setImgUrl(img.getImgUrl());
                        skuImagesEntity.setDefaultImg(img.getDefaultImg());
                        return skuImagesEntity;
                    }).filter(img -> !StringUtils.isEmpty(img.getImgUrl()))
                    .collect(Collectors.toList());

            //6.2 保存sku的图片信息;pms_spu_images
            //todo 无图片的不保存
            skuImagesService.saveBatch(imagesEntities);

            List<Attr> attr = item.getAttr();
            List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = attr.stream()
                    .map(attr1 -> {
                        SkuSaleAttrValueEntity attrValueEntity = new SkuSaleAttrValueEntity();
                        BeanUtils.copyProperties(attr1, attrValueEntity);
                        attrValueEntity.setSkuId(skuId);
                        return attrValueEntity;
                    }).collect(Collectors.toList());
            //6.3 sku的销售属性信息;pms_spu_sale_attr_value
            skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntities);

            //6.4 sku的优惠、满减等信息;shopping_sms -> sms_sku_ladder/sms_sku_full_reduction/sms_member_price
            SkuReductionTo skuReductionTo = new SkuReductionTo();
            BeanUtils.copyProperties(item, skuReductionTo);
            skuReductionTo.setSkuId(skuId);
            int compareTo = skuReductionTo.getFullPrice().compareTo(new BigDecimal(0));
            if (skuReductionTo.getFullCount() > 0 || compareTo > 0) {
                R r = couponFeignService.saveSkuReduction(skuReductionTo);
                if (r.getCode() != 0) {
                    log.error("远程保存sku积分信息失败");
                }
            }
            // 6.5新增商品后立马在库存里增加库存为0的数据,仓库先默认为1
            addWareSku(skuId, 1L);
        });
    }

    @Override
    public void saveBaseSpuInfo(SpuInfoEntity spuInfoEntity) {
        this.baseMapper.insert(spuInfoEntity);
    }

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)) {
            wrapper.and(w -> w.eq("id", key).or().like("spu_name", key));
        }
        String status = (String) params.get("status");
        if (!StringUtils.isEmpty(status)) {
            wrapper.eq("publish_status", status);
        }
        String brandId = (String) params.get("brandId");
        if (!StringUtils.isEmpty(brandId) && !Constant.SEARCH_IGNORE_VALUE_ZERO.equals(brandId)) {
            System.out.println("brandId = " + brandId);
            wrapper.eq("brand_id", brandId);
        }
        String catelogId = (String) params.get("catelogId");
        if (!StringUtils.isEmpty(catelogId) && !Constant.SEARCH_IGNORE_VALUE_ZERO.equals(catelogId)) {
            System.out.println("catelogId = " + catelogId);
            //todo 数据库字段可能写错了,应该是catelog_id. entity与xml应该也是catelog_id
            wrapper.eq("catalog_id", catelogId);
        }

        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                wrapper
        );

        return new PageUtils(page);

    }

    @Override
    public void up(Long spuId) {
        // 查出当前spuid对应所有的sku信息,品牌
        List<SkuInfoEntity> skuList = skuInfoService.getSkuBySpuId(spuId);

        // todo 4.查询当前的sku的所有可以被用来检索的的规格属性
        List<ProductAttrValueEntity> baseValue = attrValueService.baseAttrListForSpu(spuId);
        // 提取所有attrId
        List<Long> attrIds = baseValue.stream()
                .map(ProductAttrValueEntity::getAttrId)
                .collect(Collectors.toList());
        // 然后到attr表查询该attrId的searchType是否为1
        List<Long> searchAttrIds = attrService.selectSearchAttrs(attrIds);

        Set<Long> idSet = new HashSet<>(searchAttrIds);

        List<SkuEsModel.Attr> attrList = baseValue.stream()
                .filter(item -> idSet.contains(item.getAttrId()))
                .map(item -> {
                    SkuEsModel.Attr attr = new SkuEsModel.Attr();
                    BeanUtils.copyProperties(item, attr);
                    return attr;
                })
                .collect(Collectors.toList());


        // todo 1.先要判断是否有库存
        List<Long> skuIdList = skuList.stream()
                .map(SkuInfoEntity::getSkuId)
                .collect(Collectors.toList());
        Map<Long, Boolean> stockMap = null;
        try {

            R hasStock = wareFeignService.getSkuHasStock(skuIdList);
            /*  由于雷神的工程量太大了,干脆偷下懒
                雷神那有问题给R设置了泛型可能会导致拿不到数据
                弹幕大神总结原因:
                    这里没用是因为Jackson对于HashMap类型会有特殊的处理方式，
                    具体来说就是会对类进行向上转型为Map，导致子类的私有属性消失
            * */
            @SuppressWarnings("unchecked")
            List<SkuHasStockVo> voList = (List<SkuHasStockVo>) hasStock.get("data");
            stockMap = voList.stream()
                    .collect(Collectors.toMap(SkuHasStockVo::getSkuId,
                            SkuHasStockVo::getHasStock)
                    );
        } catch (Exception e) {
            log.error("查询库存出现异常: {}", e);
        }


        // 封装每个sku的信息
        Map<Long, Boolean> finalStockMap = stockMap;
        List<SkuEsModel> upProducts = skuList.stream()
                .map(sku -> {
                    SkuEsModel esModel = new SkuEsModel();
                    BeanUtils.copyProperties(sku, esModel);
                    // 有些变量需要copy但名字不同,需要手动copy
                    esModel.setSkuPrice(sku.getPrice());
                    esModel.setSkuImg(sku.getSkuDefaultImg());

                    // 默认为true
                    if (CollectionUtils.isEmpty(finalStockMap)) {
                        esModel.setHasStock(true);
                    } else {
                        esModel.setHasStock(finalStockMap.get(sku.getSkuId()));
                    }

                    // 2.热度评分,先默认为0
                    esModel.setHotScore(0L);
                    // 3.查询品牌的名字和分类的名字信息
//                    todo es保存错误可能的位置 BrandEntity brand = brandService.getById(sku.getBrandId());
                    BrandEntity brand = brandService.getById(sku.getBrandId());
//                    BrandEntity brand = brandService.getById(esModel.getBrandId());
                    esModel.setBrandName(brand.getName());
                    esModel.setBrandImg(brand.getLogo());

//                    todo es保存错误可能的位置 CategoryEntity category = categoryService.getById(sku.getCatalogId());
                    CategoryEntity category = categoryService.getById(sku.getCatalogId());
//                    CategoryEntity category = categoryService.getById(esModel.getCatalogId());
                    esModel.setCatalogName(category.getName());

                    // 设置检索属性
                    esModel.setAttrs(attrList);

                    return esModel;
                }).collect(Collectors.toList());

        // 5.将数据发送给es保存
        R r = searchFeignService.productStatusUp(upProducts);
        // 调用成功要修改上架状态
        if (r.getCode() == 0) {
            SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
            spuInfoEntity.setId(spuId);
            spuInfoEntity.setPublishStatus(ProductConstant.StatusEnum.UP_SPU.getCode());
            baseMapper.updateById(spuInfoEntity);
        } else {
            // todo 如果失败 考虑下 重复调动 接口幂等性
        }

    }


}
